package entities;

import com.haxepunk.Entity;
import com.haxepunk.Graphic;
import com.haxepunk.graphics.Spritemap;
import com.haxepunk.Mask;
import com.haxepunk.math.Vector;
import flash.geom.Point;
import com.haxepunk.utils.Input;
import com.haxepunk.utils.Key;
import com.haxepunk.tmx.TmxObject;
import com.haxepunk.HXP;
import nape.phys.Material;
import nape.shape.Polygon;
import nape.util.BitmapDebug;

import nape.constraint.Constraint;
import nape.constraint.WeldJoint;
import nape.dynamics.Arbiter;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.Compound;
import nape.shape.Circle;
import nape.shape.Shape;
import nape.space.Space;

import com.haxepunk.nape.NapeEntity;
import nape.phys.BodyType;
import nape.constraint.PivotJoint;

import nape.util.Debug;

/**
 * ...
 * @author Marcelo Ruben Guardia
 */
class KamikazeNapeMO2D extends NapeEntity
{
	
	private var bezierMO2D : CurveBezierMO2D = null;
	private var banzai:Bool = false;
	private var drawing:Bool = true;
	private var bezierPointsLoaded:Bool = false;
	private var spKamikaze : Spritemap;
	private var pointsForCurve : Int = 3;
	private var countPoints : Int = 0;
	private var bezierPoints : Array<flash.geom.Point>;
	private var bezierPointsAngles:Array<Float>;
	private var duration:Float = 1.0;
	private var timeBezier:Float = 0.0;
	private var timeStep:Float = 0.005;// 0.05;
	private var indexBezierPoint:Int = 0;
	
	private var bodyAux:Body;
	private var debugNape:Debug;
	private var space:Space;
	
	private var deltaX:Float = 0.0;
	private var deltaY:Float = 0.0;	

	/**
		* @param	obj : objeto leído en el nivel tmx del formato tiled 
	 * @param	space : Space world del Engine Nape en el cual se debe agregar el body del actual objeto
		* con las propiedades physics para interactuar.
	 */
	public function new(obj : TmxObject, spaceNape : Space = null)
	{
		
		super();
		space = spaceNape;
		SetBodiesNape(obj, spaceNape);

		set_name("KamikazeNapeMO2D");
		
		//spKamikaze = new Spritemap(GC.IMG_kamikaze_, 110, 48);
		spKamikaze = new Spritemap("gfx/kamikaze2.png", 80, 38);
		spKamikaze.add("flying", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], 5);
		spKamikaze.play("flying");		
		spKamikaze.centerOrigin();
		graphic = spKamikaze;

		bezierMO2D = new CurveBezierMO2D(body.position.x , body.position.y);
		
		countPoints++;
		bezierPoints = new Array<flash.geom.Point>();
		bezierPointsAngles = new Array < Float >();
		
		debugNape = new BitmapDebug(Std.int(HXP.stage.width), Std.int(HXP.stage.height), HXP.stage.color);
		
		
		//trace("KamikazeNapeMO2D IDEA: Tener distintos tipos de aviones, ej: uno con ametralladora, otro tira bombas, otro misiles");
		//followCamera = true;
}

	private function SetBodiesNape(obj:TmxObject, spaceNape:Space):Void
	{
		// body heredado de NapeEntity
		body = new Body(BodyType.DYNAMIC);
		body.position.setxy(obj.x, obj.y);
		
		var localVerts:Array<Vec2> = new Array<Vec2>();

		// vertices de la cabina del avion
		localVerts.push(new Vec2(27, 5));
		localVerts.push(new Vec2(10, -12));
		localVerts.push(new Vec2(-6, -12));
		
		localVerts.push(new Vec2( -18, -3));
		localVerts.push(new Vec2( -18, 17));
		
		localVerts.push(new Vec2(-7, 19));		
		localVerts.push(new Vec2(2, 19));		
		localVerts.push(new Vec2(19, 17));		
		localVerts.push(new Vec2(27, 5));		
		
		body.shapes.add(new Polygon(localVerts));

		/*
				Construct a new Material object.	parameters
				elasticity :: 0 : The coeffecient of elasticity for material.
				dynamicFriction :: 1 : The coeffecient of dynamic friction for material.
				staticFriction :: 2 : The coeffecient of static friction for material.
				density :: 1 : The density of the shape using this material in units of g/pixel/pixel.
				rollingFriction :: 0.001 : The coeffecient of rolling friction for material used in circle friction computations.
				returns	The constructed Material object.
		*/
		// Material(elasticity=0, dynamicFriction=1, staticFriction=2, density=1, rollingFriction=0.001));//default values
		//body.setShapeMaterials(new Material(0, 1, 2, 1, 0.001));//default values
		body.setShapeMaterials(new Material(1, 0.2, 0.5, 0.5, 0.001));
		body.allowMovement = false;
		body.allowRotation = false;
		body.mass = 0.75;
		body.space = spaceNape;
		body.debugDraw = true;
		
		// body agregado en variable auxiliar
		bodyAux = new Body(BodyType.DYNAMIC);
		bodyAux.position.setxy(obj.x, obj.y);

		localVerts.splice(0, localVerts.length);// vaciando el array de vertices
		
		// vertices de la cola del avion
		localVerts.push(new Vec2( -18, -3));
		
		localVerts.push(new Vec2( -48, -12));
		localVerts.push(new Vec2( -53, 5));
		
		localVerts.push(new Vec2( -18, 17));		
		localVerts.push(new Vec2( -18, -3));
		
		bodyAux.shapes.add(new Polygon(localVerts));
		// Material(elasticity=0, dynamicFriction=1, staticFriction=2, density=1, rollingFriction=0.001));//default values
		bodyAux.setShapeMaterials(new Material(1, 0.5, 0.5, 0.5, 0.001));
		bodyAux.allowMovement = true;// false;
		bodyAux.mass = 0.2;
		bodyAux.space = spaceNape;
		
		// uniendo los bodies
		WeldJointBodies(obj);
		//PivotJointBodies(obj);
	}
	
	public function WeldJointBodies(obj:TmxObject=null):Void
	{
		var anchor = new Vec2();
		var weldJoint = new WeldJoint(
		body,
		bodyAux,
		body.worldPointToLocal(anchor, true),
		bodyAux.worldPointToLocal(anchor, true)
		);
		anchor.dispose();
		weldJoint.stiff = true;// o false;// union rigida o elastica
		weldJoint.ignore = true;// ignora colisiones con los bodies unidos
		weldJoint.debugDraw = true;
		weldJoint.space = space;
	}
	
	public function PivotJointBodies(obj:TmxObject):Void
	{
  var anchor = new Vec2((body.position.x + bodyAux.position.x) / 2, (body.position.y + bodyAux.position.y) / 2);
		var pivotJoint = new PivotJoint(
		body,
		bodyAux,
		body.worldPointToLocal(anchor, true),
		bodyAux.worldPointToLocal(anchor, true)
		);
		anchor.dispose();
		pivotJoint.stiff = true;// o false;// union rigida o elastica
		pivotJoint.ignore = true;// ignora colisiones con los bodies unidos
		pivotJoint.debugDraw = true;
		pivotJoint.space = space;
	}

	override public function update():Void
	{
		//trace(body.position+"   "+this._point);
			
		super.update();
		x = body.position.x - 15*Math.cos(angle * HXP.RAD);
		y = body.position.y - 15*Math.sin(angle * HXP.RAD);
		
		if (Input.mousePressed && countPoints <= pointsForCurve && !banzai)
		{
			bezierMO2D.AddControlPoint(new flash.geom.Point(HXP.camera.x + Input.mouseX, HXP.camera.y + Input.mouseY));
			bezierMO2D.LoadBezierPoints();
			countPoints++;
			
			if (countPoints == pointsForCurve)
			{
				banzai = true;
			}
		}
		else
		if (banzai)
		{
			MoveOnBezier();
		}
		
		if(followCamera)
			HXP.camera.setTo(x - HXP.screen.width * 0.5, y - HXP.screen.height * 0.5);
		
		if (Input.pressed(Key.SPACE))
			drawing = !drawing;
	}
	
	override public function render():Void
	{
		if (drawing)
				super.render();
		
		bezierMO2D.render();
		
		//debugNape.clear();
		//debugNape.draw(space);
		//debugNape.flush();
	}

	public function MoveOnBezier():Void
	{
		if (bezierPointsLoaded)
		{
			if (indexBezierPoint < bezierPoints.length)
			{
				//moveTo(bezierPoints[indexBezierPoint].x, bezierPoints[indexBezierPoint].y);
				body.position.setxy(
				bezierPoints[indexBezierPoint].x,
				bezierPoints[indexBezierPoint].y);
				//spKamikaze.angle = bezierPointsAngles[indexBezierPoint];
				body.rotation = bezierPointsAngles[indexBezierPoint];
				indexBezierPoint++;
				
				//trace("angle = " + angle);// * HXP.RAD);
				if (indexBezierPoint >= bezierPoints.length)
				{
					LaunchKamikaze();
				}
			}
			//else
			//{
				//
			//}
		}
		else
		{
			LoadBezierPoints();
			LoadBezierPointsAngles();
			bezierPointsLoaded = true;
		}
		

	}
	
	public function LoadBezierPoints():Void
	{
		// borra todos los puntos guardados
		bezierPoints.splice(0, bezierPoints.length);

		var LOD = countPoints * 40;
		var dt = 1.0 / (LOD - 1.0);
		//trace("dt = "+dt);
		var k = 0;
		while (k < LOD)
		{
			var t = dt * k;
			if (t <= 1.0)
				t -= 0.00001;
			
			bezierPoints.push(bezierMO2D.Calculate(t));
			
			k++;
		}
		
	}
	
	public function LoadBezierPointsAngles():Void
	{
		for (bp in 0...(bezierPoints.length-1))
		{
			var dx:Float = bezierPoints[bp + 1].x - bezierPoints[bp].x;
			var dy:Float = bezierPoints[bp + 1].y - bezierPoints[bp].y;
			bezierPointsAngles.push( (Math.atan2( dy, dx )));						
		}
		
		// correccion del angulo para el ultimo punto de la curva
		bezierPointsAngles[bezierPointsAngles.length] = bezierPointsAngles[bezierPointsAngles.length - 1];
		// deltas de variacion para la velocidad instantanea en el ultimo punto de la curva
		deltaX = bezierPoints[bezierPoints.length - 1].x - bezierPoints[bezierPoints.length-2].x;
		deltaY = bezierPoints[bezierPoints.length - 1].y - bezierPoints[bezierPoints.length-2].y;		
	}
	
	public function LaunchKamikaze():Void
	{
		//trace("Baaannnzaaaiii!!!");
		body.allowMovement = true;
		body.allowRotation = true;
		bodyAux.allowMovement = true;
		
		// se podria calcular el power de impulse con el modulo del vector
		// desde el penultimo punto hasta el ultimo punto sobre la curva
		var power = 50;
		var power2 = 10;
		//var impulse:Vec2 = new Vec2( power * Math.cos( angle * HXP.RAD), power * Math.sin( angle * HXP.RAD));
		var impulse:Vec2 = new Vec2(deltaX * power, deltaY * power);
		
		//trace("angle = " + angle + "  impulse = " + impulse);
		//body.force = impulse;
		
		body.applyImpulse(impulse, null, true);
		//bodyAux.applyImpulse(impulse, null, true);
	}
	
}